<template>
  <div class="home">
    <h1 class="title">这里是xxxxxx页</h1>
    <div style="position: relative" ref="mmpRef">
      <div style="position:absolute;left:0;top:0;opacity:0.5;height: 35px;width: 100%;z-index: 9999;display: flex;justify-content: flex-start;align-items: center;padding: 0 20px">
        <el-button @click="state.play">启动动画</el-button>
        <el-button @click="state.stop">关闭动画</el-button>
      </div>
      <div ref="aircraft"></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  Scene,
  PerspectiveCamera,
  WebGL1Renderer,
  AmbientLight,
  MeshBasicMaterial,
  PlaneBufferGeometry,
  Mesh,
  GridHelper,
  DoubleSide,
  AnimationMixer,
  Clock,
  Vector2,
  Vector3,
  Color,
  Raycaster,
  DirectionalLight,
  AxesHelper, AnimationClip
} from 'three'
// import TWEEN from "@tweenjs/tween.js";
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { AnimationAction } from "three/src/animation/AnimationAction";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";

const loading = ref(true)
const aircraft = ref<HTMLDivElement>()
const action = ref<AnimationAction>();
const handfbx = new URL('./hand.fbx', import.meta.url).href;
const screenWidth = 1200;
const screenHeight = 500;
const mouse:any = new Vector2();
const raycaster:any = new Raycaster();
const mmpRef:any = ref(null);
let selectedObjects = [], composer = null, renderPass = null, outlinePass = null;

console.log('mouse', mouse)

let state = reactive({
  play: function () {
    action.value && action.value.play()
  },
  stop: function () {
    action.value && action.value.stop()
  }
})

const init = () => {
  const scene = new Scene()
  /**
   * 相机 PerspectiveCamera(视野大小, 视图的长宽比, 近景， 远景)
   */
  const camera = new PerspectiveCamera(75, screenWidth/screenHeight, 1, 1000)
  camera.position.set(0, 30, 30)
  camera.lookAt(scene.position)

  /**
   * antialias消除锯齿
   */
  const renderer = new WebGL1Renderer({antialias: true})
  // 背景颜色
  renderer.setClearColor(0xffffff)
  // 设置设备像素比
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(screenWidth, screenHeight)
  // 设置窗口的大小  适合在一些小地方显示
  // renderer.setViewport(0, 0, 200, 200)

  const animationMixer = new AnimationMixer(scene)
  const clock = new Clock()

  // 添加平面
  const planeBufferGeometry = new PlaneBufferGeometry(100, 100)
  const plane = new Mesh(planeBufferGeometry, new MeshBasicMaterial({color: 0xFFFFFF, side: DoubleSide}))
  plane.rotation.x = Math.PI / 2
  scene.add(plane)
  // 添加一个网格
  scene.add(new GridHelper(100, 100))

  let fbxLoader = new FBXLoader()
  fbxLoader.load(handfbx, function (fbx:any) {
    console.log("fbx", fbx)
    console.log("子元素", fbx.children)
    console.log("子元素uuid", fbx.children.map((im:any)=> im.uuid))
    fbx.scale.set(1, 1, 1)
    fbx.position.set(1, 9, 1)
    scene.add(fbx);
    loading.value = false
    // const animations: AnimationClip = fbx.animations.find(animationsClip => animationsClip.name === 'Take 001')!
    // action.value = animationMixer.clipAction(animations)
  })

  // 添加环境灯光
  scene.add(new AmbientLight(0xFFFFFF, 1))
  const axesHelper = new AxesHelper( 5 );
  scene.add( axesHelper );

  // 平行光
  const directionalLight = new DirectionalLight(0xffffff);
  directionalLight.position.set(-100, 100, 30);
  directionalLight.castShadow = true;
  scene.add(directionalLight);
  const directionalLight3 = new DirectionalLight(0xffffff);
  directionalLight3.position.set(100, -100, -10);
  directionalLight3.castShadow = true;
  scene.add(directionalLight3);

  aircraft.value?.appendChild(renderer.domElement)
  window.addEventListener('resize', () => onWindowResize())

  /**
   * 轨道控制器 也就是鼠标转动等操作
   */
  let orbitControls = new OrbitControls(camera, renderer.domElement)
  // 放大缩小
  // orbitControls.enableZoom = false
  orbitControls.autoRotateSpeed = 1

  renderScene()

  function renderScene(){
    requestAnimationFrame(renderScene)
    animationMixer.update(clock.getDelta())
    // const boxs = scene.getObjectByName('box') // 上面如果设置了name 就可以这样子取
    renderer.render(scene, camera)
  }

  const outlineObj = (selectedObjects:any) => {
    // 创建一个EffectComposer（效果组合器）对象，然后在该对象上添加后期处理通道。
    composer = new EffectComposer(renderer);
    // 新建一个场景通道  为了覆盖到原理来的场景上
    renderPass = new RenderPass(scene, camera);
    composer.addPass(renderPass);
    // 物体边缘发光通道
    outlinePass = new OutlinePass(
        new Vector2(window.innerWidth, window.innerHeight),
        scene,
        camera,
        selectedObjects
    );
    outlinePass.edgeStrength = 8.0; // 高光边缘边框的亮度
    outlinePass.edgeGlow = 1; // 光晕[0,1]  边缘微光强度
    outlinePass.usePatternTexture = false; // 是否使用父级的材质，纹理覆盖
    outlinePass.edgeThickness = 3; // 边框宽度，高光厚度
    outlinePass.downSampleRatio = 1; // 边框弯曲度
    outlinePass.pulsePeriod = 2; // 呼吸闪烁的速度，数值越大，律动越慢
    outlinePass.visibleEdgeColor.set(parseInt(`0x00f6ff`)); // 呼吸显示的颜色
    outlinePass.hiddenEdgeColor = new Color(0, 0, 0); // 呼吸消失的颜色
    // outlinePass.clear = true
    composer.addPass(outlinePass); // 加入高光特效
    outlinePass.selectedObjects = selectedObjects; // 需要高光的模型
  }

  // console.log('renderer', renderer.domElement.getBoundingClientRect().top, renderer.domElement.getBoundingClientRect().left)

  const initTween = (targetX:any, targetY:any, targetZ:any) => {
    // 获取当前相机位置
    let initPosition = {
        x: camera.position.x,
        y: camera.position.y,
        z: camera.position.z,
    };
    //定义相机移动方法
    let tween = new TWEEN.Tween(initPosition)
        .to({ x: targetX, y: targetY, z: targetZ }, 2000)
        .easing(TWEEN.Easing.Sinusoidal.InOut);
    //格子位置参数
    let onUpdate = (pos) => {
        let x = pos.x;
        let y = pos.y;
        let z = pos.z;
        //z<0为背面格子，z>0为正面格子，并设置相机的位置
        if (pos.z < 0) {
            camera.position.set(x, y, z - 12);
        } else {
            camera.position.set(x, y, z + 12);
        }
    };
    //调用相机方法并传入格子位置参数
    tween.onUpdate(onUpdate);
    tween.start();
    //设置相机target位置（相机看向格子的位置）
    if (positionObj.z < 0) {
        controls.target.set(
            positionObj.x,
            positionObj.y - 0.4,
            -12
        );
    } else {
        controls.target.set(
            positionObj.x,
            positionObj.y - 0.4,
            12
        );
    }
  }


  // 鼠标点击模型
  const onMouseClick = (event:any) => {
    //通过鼠标点击的位置计算出raycaster所需要的点的位置，以屏幕中心为原点，值的范围为-1到1
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / (window.innerHeight)) * 2 + 1;

    /** 获取点击点位于射线上的位置，值在-1和1之间，此写法适用于模型不在全屏下渲染的场景中(页面局部渲染) */
    mouse.x = ((event.clientX - renderer.domElement.getBoundingClientRect().left) / renderer.domElement.offsetWidth) * 2 - 1;
    mouse.y = -((event.clientY - renderer.domElement.getBoundingClientRect().top) / renderer.domElement.offsetHeight) * 2 + 1;

    // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
    raycaster.setFromCamera(mouse, camera);
    // 获取raycaster直线和所有模型相交的数组集合
    let intersects = raycaster.intersectObjects(scene.children);
    console.log("鼠标点击", intersects.map((im:any)=>im.object.name))
    if (!intersects[0]) {
      return;
    } else {
      //这样会获取所有模型，因为我们这里只需要小格子
      //所以只需要获取我们之前设置name!=""属性的object即可
      if (!intersects[0].object.name == "") {
          selectedObjects = [];
          selectedObjects.push(intersects[0].object);
          //调用高亮显示模型（呼吸灯）的方法给点击的格子添加点击后的样式
          outlineObj(selectedObjects);
          // //拿到格子的position坐标
          // let positionObj = {
          //   x: intersects[0].object.position.x,
          //   y: intersects[0].object.position.y,
          //   z: intersects[0].object.position.z,
          // };
          // //调用机移动动画，将相机移动至被点击的格子处
          // initTween(
          //   positionObj.x,
          //   positionObj.y,
          //   positionObj.z
          // );
          // //点击格子后，开放返回主视角的点击权限
          // isDisabled = false;
          // //点击格子后，禁止模型自动旋转
          // controls.autoRotate = false;
      }
    }
  }

  renderer.domElement.onclick = onMouseClick;


  const onWindowResize = () => {
    renderer.setSize(screenWidth, screenHeight)
    camera.aspect = screenWidth / screenHeight
    camera.updateProjectionMatrix()
  }
}

onMounted(() => {
  init()
})

</script>

<style lang="scss" scoped>
</style>
